org 0100h
jmp STARTMAIN
OEMName DB 'Gensh...'
SectorSize DW 512
SectorClus DB 1
ReservedSector DW 1
FATNum DB 2
RootCNT DW 224
TOTSEC16 DW 2880
Media DB 0xF0
FatSize16 DW 9
TrkSec DW 18
HeadNum DW 2
SecHidden DD 0
TOTSEC32 DD 0
DriveNum DB 0
Reserved1 DB 0
BootSig DB 29h
VolID DD 0
VolLabel DB 'Ge...Impact'
FileSystemType DB 'FAT12   '
FATSz equ 9
RootDirSectors equ 14
SectorNoOfRootDirectory equ 19
SectorNoOfFAT1 equ 1
DeltaSectorNo equ 17
LoaderStart equ 09000h
LoaderOffset equ 0100h
LoaderStartPhyAddr equ 09000h*10h
KernelFileStart equ 08000h
KernelFileOffset equ 0h
KernelFileStartPhyAddr equ 08000h*10h
KernelEntryPointPhyAddr equ 030400h
PageDirBase equ 200000h
PageTblBase equ 201000h
DA32  EQU 4000h
DALIMIT4K EQU 8000h
DADPL0 EQU 00h
DADPL1 EQU 20h
DADPL2 EQU 40h
DADPL3 EQU 60h
DADR EQU 90h
DADRW EQU 92h
DADRWA EQU 93h
DAC EQU 98h
DACR EQU 9Ah
DACCO EQU 9Ch
DACCOR EQU 9Eh
DALDT EQU 82h
DATaskGate EQU 85h
DA386TSS EQU 89h
DA386CGate EQU 8Ch
DA386IGate EQU 8Eh
DA386TGate EQU 8Fh
SARPL0 EQU 0
SARPL1 EQU 1
SARPL2 EQU 2
SARPL3 EQU 3
SATIG EQU 0
SATIL EQU 4
PGP EQU 1
PGRWR EQU 0
PGRWW EQU 2
PGUSS EQU 0
PGUSU EQU 4
%macro GateDescriptor 3
     dw %2&0FFFFh
     dw %1&0FFFFh
     db (%1>>16)&0FFh
     dw ((%2>>8)&0F00h)|(%3&0F0FFh)
     db (%1>>24)&0FFh
%endmacro
%macro Gate 4
     dw	(%2&0FFFFh)
     dw	%1
     dw	(%3&1Fh)|((%4<<8)&0FF00h)
     dw	((%2>>16)&0FFFFh)
%endmacro
STARTGDT:GateDescriptor 0,0,0
STARTDESCFLATC:GateDescriptor 0,0fffffh,DACR |DA32|DALIMIT4K
STARTDESCFLATRW:GateDescriptor 0,0fffffh,DADRW|DA32|DALIMIT4K
STARTDESCVIDEO:GateDescriptor  0B8000h,0ffffh,DADRW|DADPL3
GdtLen equ $-STARTGDT
GdtPtr dw GdtLen-1
     dd LoaderStartPhyAddr+STARTGDT
SelectorFlatC  equ STARTDESCFLATC-STARTGDT
SelectorFlatRW  equ STARTDESCFLATRW-STARTGDT
SelectorVideo  equ STARTDESCVIDEO-STARTGDT+SARPL3
BaseOfStack equ 0100h
STARTMAIN:
     mov ax,cs
     mov ds,ax
     mov es,ax
     mov ss,ax
     mov sp,BaseOfStack
     mov dh,0
     call DispStrRealMode
     mov ebx,0
     mov di,_MemChkBuf
.MemChkLoop:
     mov eax,0E820h
     mov ecx,20
     mov edx,0534D4150h
     int 15h
     jc .MemChkFail
     add di,20
     inc dword [_dwMCRNumber]
     cmp ebx,0
     jne .MemChkLoop
     jmp .MemChkOK
.MemChkFail:
     mov dword [_dwMCRNumber],0
.MemChkOK:
     mov word [wSectorNo],SectorNoOfRootDirectory 
     xor ah,ah
     xor dl,dl
     int 13h
STARTSEARCHINROOTDIRBEGIN:
     cmp word [wRootDirSizeForLoop],0
     jz STARTNOKERNELBIN
     dec word [wRootDirSizeForLoop]
     mov ax,KernelFileStart
     mov es,ax
     mov bx,KernelFileOffset
     mov ax,[wSectorNo]
     mov cl,1
     call ReadSector
     mov si,KernelFileName
     mov di,KernelFileOffset
     cld
     mov dx,10h
STARTSEARCHFORKERNELBIN:
     cmp dx,0
     jz STARTGOTONEXTSECTORINROOTDIR
     dec dx
     mov cx,11
STARTCMPFILENAME:
     cmp cx,0
     jz STARTFILENAMEFOUND
     dec cx
     lodsb
     cmp al,byte [es:di]
     jz STARTGOON
     jmp STARTDIFFERENT
STARTGOON:
     inc di
     jmp STARTCMPFILENAME
STARTDIFFERENT:
     and di,0FFE0h
     add di,20h
     mov si,KernelFileName
     jmp STARTSEARCHFORKERNELBIN
STARTGOTONEXTSECTORINROOTDIR:
     add word [wSectorNo],1
     jmp STARTSEARCHINROOTDIRBEGIN
STARTNOKERNELBIN:
     mov dh,2
     call DispStrRealMode
     jmp $
STARTFILENAMEFOUND:
     mov ax,RootDirSectors
     and di,0FFF0h
     push eax
     mov eax,[es : di+01Ch]
     mov dword [dwKernelSize],eax
     pop eax
     add di,01Ah
     mov cx,word [es:di]
     push cx
     add cx,ax
     add cx,DeltaSectorNo
     mov ax,KernelFileStart
     mov es,ax
     mov bx,KernelFileOffset
     mov ax,cx
STARTGOONLOADINGFILE:
     push ax
     push bx
     mov ah,0Eh
     mov al,'!'
     mov bl,0Fh
     int 10h
     pop bx
     pop ax
     mov cl,1
     call ReadSector
     pop ax
     call GetFATEntry
     cmp ax,0FFFh
     jz STARTFILELOADED
     push ax
     mov dx,RootDirSectors
     add ax,dx
     add ax,DeltaSectorNo
     add bx,[SectorSize]
     jmp STARTGOONLOADINGFILE
STARTFILELOADED:
     call KillMotor
     mov dh,1
     call DispStrRealMode
     lgdt [GdtPtr]
     cli
     in al,92h
     or al,00000010b
     out 92h,al
     mov eax,cr0
     or eax,1
     mov cr0,eax
     jmp dword SelectorFlatC:(LoaderStartPhyAddr+STARTPMSTART)
wRootDirSizeForLoop dw RootDirSectors
wSectorNo  dw 0
bOdd   db 0
dwKernelSize  dd 0
KernelFileName  db "KERNEL  BIN",0
MessageLength  equ 9
LoadMessage:db "Genshin  "
Message1  db "Impact   "
Message2  db "Failed!!!"
DispStrRealMode:
     mov ax,MessageLength
     mul dh
     add ax,LoadMessage
     mov bp,ax
     mov ax,ds
     mov es,ax
     mov cx,MessageLength
     mov ax,01301h
     mov bx,0007h
     mov dl,0
     add dh,3
     int 10h
     ret
ReadSector:
     push bp
     mov bp,sp
     sub esp,2
     mov byte [bp-2],cl
     push bx
     mov bl,[TrkSec]
     div bl
     inc ah
     mov cl,ah
     mov dh,al
     shr al,1
     mov ch,al
     and dh,1
     pop bx
     mov dl,[DriveNum]
.GoOnReading:
     mov ah,2
     mov al,byte [bp-2]
     int 13h
     jc .GoOnReading
     add esp,2
     pop bp
     ret
GetFATEntry:
     push es
     push bx
     push ax
     mov ax,KernelFileStart
     sub ax,0100h
     mov es,ax
     pop ax
     mov byte [bOdd],0
     mov bx,3
     mul bx
     mov bx,2
     div bx
     cmp dx,0
     jz STARTEVEN
     mov byte [bOdd],1
STARTEVEN:
     xor dx,dx
     mov bx,[SectorSize]
     div bx
     push dx
     mov bx,0
     add ax,SectorNoOfFAT1
     mov cl,2
     call ReadSector
     pop dx
     add bx,dx
     mov ax,[es:bx]
     cmp byte [bOdd],1
     jnz STARTEVEN2
     shr ax,4
STARTEVEN2:
     and ax,0FFFh
STARTGETFATENRYOK:
     pop bx
     pop es
     ret
KillMotor:
     push dx
     mov dx,03F2h
     mov al,0
     out dx,al
     pop dx
     ret
[SECTION .s32]
ALIGN 32
[BITS 32]
STARTPMSTART:
     mov ax,SelectorVideo
     mov gs,ax
     mov ax,SelectorFlatRW
     mov ds,ax
     mov es,ax
     mov fs,ax
     mov ss,ax
     mov esp,TopOfStack
     push szMemChkTitle
     call DispStr
     add esp,4
     call DispMemInfo
     call SetupPaging
     call InitKernel
     jmp SelectorFlatC:KernelEntryPointPhyAddr
DispAL:
     push ecx
     push edx
     push edi
     mov edi,[dwDispPos]
     mov ah,0Fh
     mov dl,al
     shr al,4
     mov ecx,2
.begin:
     and al,01111b
     cmp al,9
     ja .1
     add al,'0'
     jmp .2
.1:
     sub al,0Ah
     add al,'A'
.2:
     mov [gs:edi],ax
     add edi,2
     mov al,dl
     loop .begin
     mov [dwDispPos],edi
     pop edi
     pop edx
     pop ecx
     ret
DispInt:
     mov eax,[esp+4]
     shr eax,24
     call DispAL
     mov eax,[esp+4]
     shr eax,16
     call DispAL
     mov eax,[esp+4]
     shr eax,8
     call DispAL
     mov eax,[esp+4]
     call DispAL
     mov ah,07h
     mov al,'h'
     push edi
     mov edi,[dwDispPos]
     mov [gs:edi],ax
     add edi,4
     mov [dwDispPos],edi
     pop edi
     ret
DispStr:
     push ebp
     mov ebp,esp
     push ebx
     push esi
     push edi
     mov esi,[ebp+8]
     mov edi,[dwDispPos]
     mov ah,0Fh
.1:
     lodsb
     test al,al
     jz .2
     cmp al,0Ah
     jnz .3
     push eax
     mov eax,edi
     mov bl,160
     div bl
     and eax,0FFh
     inc eax
     mov bl,160
     mul bl
     mov edi,eax
     pop eax
     jmp .1
.3:
     mov [gs:edi],ax
     add edi,2
     jmp .1
.2:
     mov [dwDispPos],edi
     pop edi
     pop esi
     pop ebx
     pop ebp
     ret
DispReturn:
     push szReturn
     call DispStr
     add esp,4
     ret
MemCpy:
     push ebp
     mov ebp,esp
     push esi
     push edi
     push ecx
     mov edi,[ebp+8]
     mov esi,[ebp+12]
     mov ecx,[ebp+16]
.1:
     cmp ecx,0
     jz .2
     mov al,[ds:esi]
     inc esi
     mov byte [es:edi],al
     inc edi
     dec ecx
     jmp .1
.2:
     mov eax,[ebp+8]
     pop ecx
     pop edi
     pop esi
     mov esp,ebp
     pop ebp
     ret
DispMemInfo:
     push esi
     push edi
     push ecx
     mov esi,MemChkBuf
     mov ecx,[dwMCRNumber]
.loop:
     mov edx,5
     mov edi,ARDStruct
.1:
     push dword [esi]
     call DispInt
     pop eax
     stosd
     add esi,4
     dec edx
     cmp edx,0
     jnz .1
     call DispReturn
     cmp dword [dwType],1
     jne .2
     mov eax,[dwBaseAddrLow]
     add eax,[dwLengthLow]
     cmp eax,[dwMemSize]
     jb .2
     mov [dwMemSize],eax
.2:
     loop .loop
     call DispReturn
     push szRAMSize
     call DispStr
     add esp,4
     push dword [dwMemSize]
     call DispInt
     add esp,4
     pop ecx
     pop edi
     pop esi
     ret
SetupPaging:
     xor edx,edx
     mov eax,[dwMemSize]
     mov ebx,400000h
     div ebx
     mov ecx,eax
     test edx,edx
     jz .noremainder
     inc ecx
.noremainder:
     push ecx
     mov ax,SelectorFlatRW
     mov es,ax
     mov edi,PageDirBase
     xor eax,eax
     mov eax,PageTblBase|PGP|PGUSU|PGRWW
.1:
     stosd
     add eax,4096
     loop .1
     pop eax
     mov ebx,1024
     mul ebx
     mov ecx,eax
     mov edi,PageTblBase
     xor eax,eax
     mov eax,PGP|PGUSU|PGRWW
.2:
     stosd
     add eax,4096
     loop .2
     mov eax,PageDirBase
     mov cr3,eax
     mov eax,cr0
     or eax,80000000h
     mov cr0,eax
     jmp short .3
.3:
     nop
     ret
InitKernel:
     xor esi,esi
     mov cx,word [KernelFileStartPhyAddr+2Ch]
     movzx ecx,cx
     mov esi,[KernelFileStartPhyAddr+1Ch]
     add esi,KernelFileStartPhyAddr
.Begin:
     mov eax,[esi+0]
     cmp eax,0
     jz .NoAction
     push dword [esi+010h]
     mov eax,[esi+04h]
     add eax,KernelFileStartPhyAddr
     push eax
     push dword [esi+08h]
     call MemCpy
     add esp,12
.NoAction:
     add esi,020h
     dec ecx
     jnz .Begin
     ret
[SECTION .data1]
ALIGN 32
STARTDATA:
_szMemChkTitle:db "BaseAddrL BaseAddrH LengthLow LengthHigh   Type",0Ah,0
_szRAMSize:db "RAM size:",0
_szReturn:db 0Ah,0
_dwMCRNumber:dd 0
_dwDispPos:dd (80*6+0)*2
_dwMemSize:dd 0
_ARDStruct:
     _dwBaseAddrLow:dd 0
     _dwBaseAddrHigh: dd 0
     _dwLengthLow:dd 0
     _dwLengthHigh:dd 0
     _dwType:dd 0
_MemChkBuf: times 256 db 0
szMemChkTitle  equ LoaderStartPhyAddr+_szMemChkTitle
szRAMSize  equ LoaderStartPhyAddr+_szRAMSize
szReturn  equ LoaderStartPhyAddr+_szReturn
dwDispPos  equ LoaderStartPhyAddr+_dwDispPos
dwMemSize  equ LoaderStartPhyAddr+_dwMemSize
dwMCRNumber  equ LoaderStartPhyAddr+_dwMCRNumber
ARDStruct  equ LoaderStartPhyAddr+_ARDStruct
     dwBaseAddrLow equ LoaderStartPhyAddr+_dwBaseAddrLow
     dwBaseAddrHigh equ LoaderStartPhyAddr+_dwBaseAddrHigh
     dwLengthLow equ LoaderStartPhyAddr+_dwLengthLow
     dwLengthHigh equ LoaderStartPhyAddr+_dwLengthHigh
     dwType  equ LoaderStartPhyAddr+_dwType
MemChkBuf  equ LoaderStartPhyAddr+_MemChkBuf
StackSpace: times 1000h db 0
TopOfStack equ LoaderStartPhyAddr+$